/*
 * Copyright (c) 2012 Johann Hanne
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/* lwIP core includes */
#include "lwip/opt.h"

#include "lwip/sys.h"
#include "lwip/timers.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/init.h"
#include "lwip/tcpip.h"
#include "lwip/netif.h"

#include "lwip/tcp.h"
#include "lwip/udp.h"
#include "lwip/dns.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"

#include <string.h>
#include <stdio.h>
#include <portio.h>

#include "sq610eth.h"

extern struct netif sq610eth_if;

#define mainTask_STACK_SIZE configMINIMAL_STACK_SIZE
#define mainTask_TASK_PRIORITY (tskIDLE_PRIORITY + 1)

static void mainTask(void *pvParameters) {
    struct udp_pcb *pcb;
    char msg[] = "blah";
    struct pbuf *p;

    pcb = udp_new();
    if (pcb == NULL) {
        fprintf(stderr, "udp_new failed\n");
    }

    for (;;) {
        p = pbuf_alloc(PBUF_TRANSPORT, sizeof(msg), PBUF_RAM);

        if (pcb == NULL) {
            fprintf(stderr, "udp_new failed\n");
        } else {
            memcpy(p->payload, msg, sizeof(msg));
            udp_sendto(pcb, p, IP_ADDR_BROADCAST, 1234);
            pbuf_free(p);
        }

        vTaskDelay(500);
    }
}

#if !configUSE_TICK_HOOK
#error configUSE_TICK_HOOK must be set
#endif

void vApplicationTickHook(void) {
    sq610eth_tick();
}

#define ethernetInputTask_STACK_SIZE configMINIMAL_STACK_SIZE
#define ethernetInputTask_TASK_PRIORITY (tskIDLE_PRIORITY + 2)

void ethernetInputTask(void *pvParameters);

void main(void) {
    struct ip_addr ipaddr, netmask, gw;

    tcpip_init(NULL, NULL);

    IP4_ADDR(&ipaddr, 192,168,9,123);
    IP4_ADDR(&gw, 192,168,9,1);
    IP4_ADDR(&netmask, 255,255,255,0);

    netif_add(&sq610eth_if, &ipaddr, &netmask, &gw, NULL, sq610eth_init, tcpip_input);
    netif_set_default(&sq610eth_if);
    netif_set_up(&sq610eth_if);

    xTaskCreate(ethernetInputTask, "ethernetInputTask", ethernetInputTask_STACK_SIZE, &sq610eth_if, ethernetInputTask_TASK_PRIORITY, (xTaskHandle *)NULL);
    xTaskCreate(mainTask, "main", mainTask_STACK_SIZE, NULL, mainTask_TASK_PRIORITY, (xTaskHandle *)NULL);
    vTaskStartScheduler();

    fprintf(stderr, "Oops: vTaskStartScheduler returned?!\n");

    for (;;)
        ;
}
